package org.grow.stable.security;

import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.io.PrintWriter;
import java.util.Arrays;

@EnableWebSecurity
public class SecurityConfigCenter extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Resource
    private ColdDaoAuthProvider coldDaoAuthProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(coldDaoAuthProvider);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //放行所有请求,不进入11链中,不进行认证和权限
        //注意对比权限验证在fsi放行,此处根本不进行身份认证,所以未登录状态可以访问的在此设置
        //匿名用户与未登录用户异同,都是后台无session,问题在于匿名用户可以是session过期问题导致的
        web.ignoring().antMatchers("/reg/**");


    }

    @Resource
    private AuthHandler authHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //http.exceptionHandling();
        http.formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .failureHandler(authHandler)
                .successHandler(authHandler).permitAll();
        http.logout()
                .logoutUrl("/logout")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
                .logoutSuccessHandler(authHandler);
        http.httpBasic().disable();
        http.csrf().disable();
        http.cors().configurationSource(corsConfigurationSource());
        http.authorizeRequests()
                //已经登录状态也就是有身份认证后进行权限测试是否通过的再次
                //匿名用户也是在此.
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

                .anyRequest().authenticated()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O fsi) {
                        //根据request中url查询拥有该权限的角色的list;
                        fsi.setSecurityMetadataSource(hotAccessDecisionMaker);
                        //根据session中查找auth获取该用户的角色的list 然后比较;
                        fsi.setAccessDecisionManager(new AffirmativeBased(
                                Arrays.asList(hotAccessDecisionMaker)
                        ));
                        return fsi;
                    }
                });
        http.exceptionHandling()
                //未认证,所以不允许访问
                .authenticationEntryPoint(((httpServletRequest, httpServletResponse, e) -> {
                    httpServletResponse.setStatus(401);
                    try (PrintWriter writer = httpServletResponse.getWriter();) {
                        writer.println( "认证失败");
                        writer.print(e.getLocalizedMessage());
                    }

                }))
                //无权限,所以不允许访问
                .accessDeniedHandler((httpServletRequest, httpServletResponse, e) -> {
                    httpServletResponse.setStatus(403);
                    try (PrintWriter writer = httpServletResponse.getWriter();) {

                        writer.println("权限不够访问资源");
                        writer.print(e.getLocalizedMessage());
                    }
                });


    }

    @Resource
    private HotAccessDecisionMaker hotAccessDecisionMaker;


    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许跨域访问的域名
        corsConfiguration.addAllowedOrigin("*");
// 请求头
        corsConfiguration.addAllowedHeader("*");
// 请求方法
        corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
        corsConfiguration.addAllowedMethod(HttpMethod.POST);
        corsConfiguration.addAllowedMethod(HttpMethod.GET);
        corsConfiguration.addAllowedMethod(HttpMethod.PUT);
        corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
        corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
// 预检请求的有效期，单位为秒。
        corsConfiguration.setMaxAge(3600L);
// 是否支持安全证书
        corsConfiguration.setAllowCredentials(true);
//        corsConfiguration.setAllowedOrigins(Arrays.asList(
//                "http://localhost:8081",
//                "http://localhost:8080"));
//        corsConfiguration.setAllowedMethods(Arrays.asList(
//                "GET","POST","PUT","DELETE","PATCH"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }



}

